import random
import time

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.scatterlayout import ScatterLayout
from kivy.uix.button import Button
from kivy.clock import Clock
from kivy.vector import Vector
from kivy.properties import NumericProperty, ObjectProperty, StringProperty
from kivy.graphics import Rectangle, Color
from functools import partial


class Plane(Rectangle):
  def __init__(self, **kwargs):
    super().__init__(**kwargs)
    self.gotoPos = self.pos
    self.speed = 5.0

  @property
  def center(self):
    return self.pos[0] + self.size[0] * 0.5, self.pos[1] + self.size[1] * 0.5

  @center.setter
  def center(self, value):
    self.pos = value[0] - self.size[0] * 0.5, value[1] - self.size[1] * 0.5

  def update(self):
    pos = Vector(self.center)
    subVector = Vector(self.gotoPos) - pos
    if subVector.length() < self.speed:
      self.center = self.gotoPos
      return
    unity = subVector.normalize()
    pos += unity * self.speed
    self.center = pos.x, pos.y


class Bullet(Rectangle):
  def __init__(self, app: 'SimpleAirBattleApp', speed: float, **kwargs):
    super().__init__(**kwargs)
    self.gotoPos = self.pos
    self.app = app
    self.speed = speed
    self.bid = kwargs['bid']

  @property
  def center(self):
    return self.pos[0] + self.size[0] * 0.5, self.pos[1] + self.size[1] * 0.5

  @center.setter
  def center(self, value):
    self.pos = value[0] - self.size[0] * 0.5, value[1] - self.size[1] * 0.5

  def update(self):
    pos = Vector(self.center)
    subVector = Vector(self.gotoPos) - pos
    if subVector.length() < self.speed:
      self.center = self.gotoPos
      self.app.game.allBullet.remove(self)
      self.app.game.canvas.remove(self)
      return
    unity = subVector.normalize()
    pos += unity * self.speed
    self.center = pos.x, pos.y
    dis = max(abs(self.center[0] - self.player.center[0]), abs(self.center[1] - self.player.center[1]))
    if dis < sum(self.size) * 0.2 + sum(self.player.size) * 0.2:
      print('dis=', dis)
      print('pos=', self.pos, self.player.pos)
      self.app.game.GameOver()

  @property
  def player(self):
    return self.app.game.player


class SimpleAirBattleUi(BoxLayout):
  fps = StringProperty('')
  lastUpdateTime = NumericProperty(0)

  def __init__(self, app, **kwargs):
    super().__init__(orientation='vertical', **kwargs)
    self.app = app
    # self.add_widget(
    #   Button(
    #     size_hint=(1, None), height=50,
    #     text='click', on_press=partial(self.app.game.AddBullet),
    #   )
    # )
    self.scoreLabel = Label(
      size_hint=(1, None), height=50,
      text='score: 0'
    )
    self.add_widget(self.scoreLabel)

  def update(self, dt):
    nowTime = time.time()
    # print('update=', self.fps)
    self.fps = 'fps: {}'.format(
      round(1 / (nowTime - self.lastUpdateTime), 1)
    )
    self.lastUpdateTime = nowTime


class SimpleAirBattleGame(FloatLayout):

  def __init__(self, app: 'SimpleAirBattleApp', **kwargs):
    super().__init__(**kwargs)
    self.allBullet = set()
    self.app = app
    self.score = 0
    self.difficulty = 0.01
    self.startTime = time.time()
    with self.canvas:
      self.player = Plane(source='plane.png', pos=(16, 16), size=(32, 32))
    self.gameOver = False

  def GameOver(self):
    self.gameOver = True
    print('GameOver!!!')
    self.app.ui.remove_widget(self.app.ui.scoreLabel)
    self.app.ui.add_widget(
      Label(text='Game Over ! score: {}'.format(self.score), font_size=88, color=(1, 1, 0))
    )

  def AddBullet(self, *args):
    # print('AddBullet=', args)
    with self.app.game.canvas:
      x = random.random() * self.app.root.width
      Color(random.random(), random.random(), random.random())
      bullet = Bullet(
        self.app, 3.0 + self.score * 0.05, bid=len(self.allBullet), size=(8, 8), pos=(x, self.app.root.height - 4)
      )
      bullet.gotoPos = (x, -4)
      self.allBullet.add(bullet)

  def update(self, dt):
    if self.gameOver:
      return
    self.player.update()
    if random.random() < self.difficulty:
      self.AddBullet()
    for bullet in list(self.allBullet):
      bullet.update()
    nowTime = time.time()
    if nowTime - self.startTime >= 0.5:
      self.score += 1
      self.difficulty += 0.005
      self.startTime = nowTime
    self.app.ui.scoreLabel.text = 'score: {}'.format(self.score)

  def on_touch_move(self, touch):
    self.player.gotoPos = touch.pos

  def on_touch_down(self, touch):
    self.player.gotoPos = touch.pos


class SimpleAirBattleApp(App):
  def __init__(self, **kwargs):
    super().__init__(**kwargs)
    self.root = BoxLayout(orientation='vertical')
    self.game = SimpleAirBattleGame(self)
    self.ui = SimpleAirBattleUi(self)

  def build(self):
    self.root.add_widget(self.game)
    self.root.add_widget(self.ui)
    Clock.schedule_interval(self.game.update, 1.0 / 60.0)
    return self.root


if __name__ == '__main__':
  SimpleAirBattleApp().run()
